package com.pactera.madp.cp.handler.sync.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.pactera.madp.common.core.util.SpringContextHolder;
import com.pactera.madp.cp.api.bo.SyncCrmProExtBo;
import com.pactera.madp.cp.api.dto.sync.SyncDTO;
import com.pactera.madp.cp.api.entity.sync.SyncStateEntity;
import com.pactera.madp.cp.common.annotations.SyncType;
import com.pactera.madp.cp.common.constant.Constants;
import com.pactera.madp.cp.common.enums.sync.CrmServiceEnum;
import com.pactera.madp.cp.common.enums.sync.SyncTypeEnum;
import com.pactera.madp.cp.common.util.sync.SyncUtils;
import com.pactera.madp.cp.config.SyncConfig;
import com.pactera.madp.cp.context.SyncStateContext;
import com.pactera.madp.cp.handler.sync.SyncTypeHandler;
import com.pactera.madp.cp.service.sync.template.SyncBusinessService;
import com.pactera.madp.cp.service.sync.template.SyncItemService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.concurrent.Executor;

@Slf4j
@Component
@SyncType(SyncTypeEnum.CRM)
public class CrmSyncHandler implements SyncTypeHandler {

    @Override
    public Boolean handler(SyncDTO dto) {
        Executor executor = SpringContextHolder.getBean(Constants.EXECUTOR_PROCESS_NAME);
        CrmServiceEnum[] crmEnums = CrmServiceEnum.values();

        String subTypeParam = dto.getSubType();
        SyncCrmProExtBo syncCrmProExtBo = JSONUtil.toBean(JSONUtil.toJsonStr(dto.getParams()), SyncCrmProExtBo.class);

        // 由于首次全量数据同步时易出现内存溢出，因此采用子线程内顺序执行
        executor.execute(() -> {
            for (CrmServiceEnum crmEnum : crmEnums) {
                if (StrUtil.isNotEmpty(subTypeParam) && !StrUtil.equals(crmEnum.getSubType(), subTypeParam)) {
                    continue;
                }
                // 获取文件日期
                String fileDate = syncCrmProExtBo.getFileDate();
                if (fileDate == null) {
                    DateTime dateTime = DateUtil.offsetDay(new Date(), -1);
                    fileDate = DateUtil.format(dateTime, Constants.DATE_FORMAT);
                }
                // 文件生成检测
                if (!checkFile(crmEnum.getSubType(), fileDate)) {
                    log.error("{}{}", crmEnum.getSubType(), "同步文件未生成完毕");
                    continue;
                }
                // 执行日志信息初始化
                SyncStateEntity syncStateEntity = new SyncStateEntity();
                syncStateEntity.setSyncType(SyncTypeEnum.CRM.getCode());
                syncStateEntity.setSyncSubType(crmEnum.getSubType());
                syncStateEntity.setFileDate(fileDate);
                SyncStateContext.set(syncStateEntity);
                try {
                    // 执行任务
                    log.debug(crmEnum.getSubType() + "执行任务开始...");

                    String subType = crmEnum.getSubType();
                    if (subType.equals(CrmServiceEnum.TAG.getSubType())
                            || subType.equals(CrmServiceEnum.ASSETS.getSubType())
                            || subType.equals(CrmServiceEnum.CUSTOM.getSubType())
                            || subType.equals(CrmServiceEnum.PRE_SAVEDEPT.getSubType())) {
                        // 大文件同步
                        Long haveReadChars = null;
                        Integer haveTotalCount = syncCrmProExtBo.getHaveTotalCount();
                        if (StrUtil.isNotEmpty(subTypeParam) && StrUtil.isNotEmpty(fileDate) && ObjectUtil.isNotNull(syncCrmProExtBo.getHaveReadChars())) {
                            haveReadChars = syncCrmProExtBo.getHaveReadChars();
                        }
                        handleBigFile(subType, crmEnum.getServiceType(), crmEnum.getBusinessServiceType(), haveReadChars, haveTotalCount);
                    } else {
                        // 一般同步
                        ((SyncItemService)SpringContextHolder.getBean(crmEnum.getServiceType())).handler();
                        // 同步数据
                        if (crmEnum.getBusinessServiceType() == null) {
                            return;
                        }
                        SyncBusinessService syncBusinessService =
                                (SyncBusinessService) SpringContextHolder.getBean(crmEnum.getBusinessServiceType());
                        if (ObjectUtil.isNotNull(syncBusinessService)) {
                            syncBusinessService.syncBusiness();
                        }
                    }

                } catch(Exception e) {
                    log.error(e.getMessage(), e);
                } finally {
                    SyncStateContext.remove();
                    // 记录执行日志
                    if (syncStateEntity.isSaveLog()) {
                        log.debug("{}{}",crmEnum.getSubType(), "记录任务执行日志");
                        syncStateEntity.insert();
                        log.debug("{}{}", crmEnum.getSubType(), "日志记录成功");
                    }
                }
            }
        });
        return Boolean.TRUE;
    }

    private boolean checkFile(String subType, String fileDate) {
        log.debug("CRM信息：check");
        String okFile = "";
        if (StrUtil.equals(CrmServiceEnum.ASSETS.getSubType(), subType)) {
            okFile = Constants.FN_CUST_ASSETS_OK;
        } else if (StrUtil.equals(CrmServiceEnum.CUSTOM.getSubType(), subType)) {
            okFile = Constants.FN_CUSTOM_OK;
        } else if (StrUtil.equals(CrmServiceEnum.TAG.getSubType(), subType)) {
            okFile = Constants.FN_CUST_TAG_OK;
        } else if (StrUtil.equals(CrmServiceEnum.PRE_SAVEDEPT.getSubType(), subType)) {
            okFile = Constants.FN_PRE_SAVEDEPT_OK;
        } else {
            return true;
        }

        SyncConfig syncConfig = SpringContextHolder.getBean(SyncConfig.class);
        String filepath = SyncUtils.buildFilePath(syncConfig.getCrmPath(), okFile, fileDate);
        return SyncUtils.checkFile(filepath);
    }

    /**
     * 大文件同步处理
     * @param serverType
     * @param businessServiceType
     */
    private void handleBigFile(String subType, Class serverType, Class businessServiceType, Long haveReadChars, Integer haveTotalCount) {
        // 是否继续读取文件
        boolean isContinue = true;
        // 忽略字符数
        long n = haveReadChars == null ? 0 : haveReadChars;
        // 已读取文件行数
        int totalCount = haveTotalCount == null ? 0 : haveTotalCount;
        int removedData = 0;

        Object[] tempData = new Object[5];
        tempData[0] = isContinue;
        tempData[1] = n;
        tempData[2] = totalCount;
        tempData[4] = removedData;
        SyncStateContext.get().setTempData(tempData);

        while (isContinue) {
            // 同步源数据
            ((SyncItemService)SpringContextHolder.getBean(serverType)).handler();

            if (!SyncStateContext.get().isSaveLog()) {
                break;
            }

            isContinue = (boolean) tempData[0];

            // 同步业务数据
            if (businessServiceType == null) {
                continue;
            }
            SyncBusinessService syncBusinessService =
                    (SyncBusinessService) SpringContextHolder.getBean(businessServiceType);
            if (ObjectUtil.isNotNull(syncBusinessService)) {
                syncBusinessService.syncBusiness();
            }
        }
        if (SyncStateContext.get().isFinalState()) {
            log.info("同步CRM【{}】数据完成", subType);
        }
    }
}
